#include <stdlib.h>
#include <stdio.h>
#include "outils.h"
#include "interface.h"
#include "main.h"
#include "ihm.h"
#include "calque.h"

/* Fonctions principales */

void interface() {
	Calque* c = firstCalque(calques);
	if (c->w >= 512 && c->h >= 512){
		int ih = 50;
		int iw = 200;
		int th = ih+c->h;
		int tw = iw+c->w;
		//Formule permettant le comportement fluide de l'ihm (((float)c->w+(float)25/* <--- Correspond au décalage par rapport à l'image*/)/(float)tw)

		//Haut
			fixeCouleur(1.0,0.1,0.1);
			writeString(0.17,0.98,"----------------------------------------");
			writeString(0.17,0.95,"--  Imagimp 2012  - Angeline & Adrien --");
			writeString(0.17,0.92,"----------------------------------------");
		//Droite
			//Liste des calques
				refreshCalques(calques, (float)c->w, (float)c->h);
			//puces rose pour la liste des commandes
				fixeCouleur((float)(204.0/255),(float)(102.0/255),(float)(204.0/255));
				drawDisque((((float)c->w+(float)25)/(float)tw),0.49,0.005);
				drawDisque((((float)c->w+(float)25)/(float)tw),0.46,0.005);
				drawDisque((((float)c->w+(float)25)/(float)tw),0.43,0.005);
				drawDisque((((float)c->w+(float)25)/(float)tw),0.40,0.005);
				drawDisque((((float)c->w+(float)25)/(float)tw),0.37,0.005);
				drawDisque((((float)c->w+(float)25)/(float)tw),0.34,0.005);
				drawDisque((((float)c->w+(float)25)/(float)tw),0.31,0.005);
				drawDisque((((float)c->w+(float)25)/(float)tw),0.28,0.005);
				drawDisque((((float)c->w+(float)25)/(float)tw),0.25,0.005);
				drawDisque((((float)c->w+(float)25)/(float)tw),0.22,0.005);
				drawDisque((((float)c->w+(float)25)/(float)tw),0.19,0.005);
				drawDisque((((float)c->w+(float)25)/(float)tw),0.16,0.005);
				drawDisque((((float)c->w+(float)25)/(float)tw),0.13,0.005);
				drawDisque((((float)c->w+(float)25)/(float)tw),0.10,0.005);
				drawDisque((((float)c->w+(float)25)/(float)tw),0.07,0.005);
				drawDisque((((float)c->w+(float)25)/(float)tw),0.04,0.005);
			//Listes des commandes qui suit les puces roses
				fixeCouleur(0.0,0.0,1.0);
				writeString((((float)c->w+(float)40)/(float)tw),0.48,"o : save image");
				writeString((((float)c->w+(float)40)/(float)tw),0.45,"z : change view");
				writeString((((float)c->w+(float)40)/(float)tw),0.42,"a : add calque");
				writeString((((float)c->w+(float)40)/(float)tw),0.39,"s : switch calque");
				writeString((((float)c->w+(float)40)/(float)tw),0.36,"d : del calque");
				writeString((((float)c->w+(float)40)/(float)tw),0.33,"m : change mix");
				writeString((((float)c->w+(float)40)/(float)tw),0.30,"<- : - opacity");
				writeString((((float)c->w+(float)40)/(float)tw),0.27,"-> : + opacity");
				writeString((((float)c->w+(float)40)/(float)tw),0.24,"x : - lum");
				writeString((((float)c->w+(float)40)/(float)tw),0.21,"w : + lum");
				writeString((((float)c->w+(float)40)/(float)tw),0.18,"v : - contraste");
				writeString((((float)c->w+(float)40)/(float)tw),0.15,"c : + contraste");
				writeString((((float)c->w+(float)40)/(float)tw),0.12,"b : invert");
				writeString((((float)c->w+(float)40)/(float)tw),0.09,"n : sepia");
				writeString((((float)c->w+(float)40)/(float)tw),0.06,"k : del LUT");
				writeString((((float)c->w+(float)40)/(float)tw),0.03,"esc : exit");
		//Fin interface
	}
	else{
		int ih = 50+(512-c->h);
		int iw = 200+(512-c->w);
		int th = ih+c->h;
		int tw = iw+c->w;

		//Haut
			fixeCouleur(1.0,0.1,0.1);
			writeString(0.17,0.98,"----------------------------------------");
			writeString(0.17,0.95,"--  Imagimp 2012  - Angeline & Adrien --");
			writeString(0.17,0.92,"----------------------------------------");
		//Droite
			//Liste des calques
				refreshCalques(calques, (float)(c->w+(512-c->w)), (float)(c->h+(512-c->h)));
			//puces rose pour la liste des commandes
				fixeCouleur((float)(204.0/255),(float)(102.0/255),(float)(204.0/255));
				drawDisque((((float)(c->w+(512-c->w))+(float)25)/(float)tw),0.52,0.005);
				drawDisque((((float)(c->w+(512-c->w))+(float)25)/(float)tw),0.49,0.005);
				drawDisque((((float)(c->w+(512-c->w))+(float)25)/(float)tw),0.46,0.005);
				drawDisque((((float)(c->w+(512-c->w))+(float)25)/(float)tw),0.43,0.005);
				drawDisque((((float)(c->w+(512-c->w))+(float)25)/(float)tw),0.40,0.005);
				drawDisque((((float)(c->w+(512-c->w))+(float)25)/(float)tw),0.37,0.005);
				drawDisque((((float)(c->w+(512-c->w))+(float)25)/(float)tw),0.34,0.005);
				drawDisque((((float)(c->w+(512-c->w))+(float)25)/(float)tw),0.31,0.005);
				drawDisque((((float)(c->w+(512-c->w))+(float)25)/(float)tw),0.28,0.005);
				drawDisque((((float)(c->w+(512-c->w))+(float)25)/(float)tw),0.25,0.005);
				drawDisque((((float)(c->w+(512-c->w))+(float)25)/(float)tw),0.22,0.005);
				drawDisque((((float)(c->w+(512-c->w))+(float)25)/(float)tw),0.19,0.005);
				drawDisque((((float)(c->w+(512-c->w))+(float)25)/(float)tw),0.16,0.005);
				drawDisque((((float)(c->w+(512-c->w))+(float)25)/(float)tw),0.13,0.005);
				drawDisque((((float)(c->w+(512-c->w))+(float)25)/(float)tw),0.10,0.005);
				drawDisque((((float)(c->w+(512-c->w))+(float)25)/(float)tw),0.07,0.005);
				drawDisque((((float)(c->w+(512-c->w))+(float)25)/(float)tw),0.04,0.005);
			//Listes des commandes qui suit les puces roses
				fixeCouleur(0.0,0.0,1.0);
				writeString((((float)(c->w+(512-c->w))+(float)40)/(float)tw),0.51,"o : save image");
				writeString((((float)(c->w+(512-c->w))+(float)40)/(float)tw),0.48,"z : change view");
				writeString((((float)(c->w+(512-c->w))+(float)40)/(float)tw),0.45,"a : add calque");
				writeString((((float)(c->w+(512-c->w))+(float)40)/(float)tw),0.42,"s : switch calque");
				writeString((((float)(c->w+(512-c->w))+(float)40)/(float)tw),0.39,"d : del calque");
				writeString((((float)(c->w+(512-c->w))+(float)40)/(float)tw),0.36,"m : change mix");
				writeString((((float)(c->w+(512-c->w))+(float)40)/(float)tw),0.33,"<- : - opacity");
				writeString((((float)(c->w+(512-c->w))+(float)40)/(float)tw),0.30,"-> : + opacity");
				writeString((((float)(c->w+(512-c->w))+(float)40)/(float)tw),0.27,"l : add LUT");
				writeString((((float)(c->w+(512-c->w))+(float)40)/(float)tw),0.24,"x : - lum");
				writeString((((float)(c->w+(512-c->w))+(float)40)/(float)tw),0.21,"w : + lum");
				writeString((((float)(c->w+(512-c->w))+(float)40)/(float)tw),0.18,"v : - contraste");
				writeString((((float)(c->w+(512-c->w))+(float)40)/(float)tw),0.15,"c : + contraste");
				writeString((((float)(c->w+(512-c->w))+(float)40)/(float)tw),0.12,"b : invert");
				writeString((((float)(c->w+(512-c->w))+(float)40)/(float)tw),0.09,"n : sepia");
				writeString((((float)(c->w+(512-c->w))+(float)40)/(float)tw),0.06,"k : del LUT");
				writeString((((float)(c->w+(512-c->w))+(float)40)/(float)tw),0.03,"esc : exit");
		//Fin interface
	}
}

void refreshCalques(ListeCalques l, float w, float h){
	int i = 0;
	Calque* c = firstCalque(calques);
	int ih = 50;
	int iw = 200;
	int th = ih+h;
	int tw = iw+w;
	char s[256] = {'\0'};

	fixeCouleur(0.1,1.0,0.0);
	writeString(((w+(float)25)/(float)tw),(0.89+i*3),"Listes des calques :");
	while(c != NULL){
		if(c == l){
			if(c->source == 0){
				sprintf(s, "-> calque %d : s <-", i);
			}
			else{
				sprintf(s, "-> calque %d : f <-", i);
			}
			writeString(((w+(float)30)/(float)tw),(0.86-(float)i*0.03)/**600+l*/, s);
		}
		else{
			if(c->source == 0){
				sprintf(s, "   calque %d : s   ", i);
			}
			else{
				sprintf(s, "   calque %d ; f   ", i);
			}
			writeString(((w+(float)30)/(float)tw),(0.86-(float)i*0.03)/**600+l*/, s);
		}
		c = c->nextCalque;
		i++;
	}
}

/// ///////////////////////////////////////////////////////////////////////////
/// fonction associée aux interruptions clavier
/// - c : caractère saisi
/// - x,y : coordonnée du curseur dans la fenetre
void kbdFunc(unsigned char c, int x, int y){
	char saisie[100] = {'\0'};
	char name[100] = {'\0'};
	int val = NULL;

	printf("Touche tapee %c (coord souris %d/%d)\n",c,x,y);
	switch(c) {
		case 't': // Exemple de saisie sur le terminal
			printf("Debraillement sur le terminal\n");
			printf("Merci de rentrer une chaine de caractère :");
			scanf("%s",saisie);
			printf("On a tape %s\n",saisie);
			break;
		case 'i': // Exemple d'utilisation des fonctions de la bibliotheque glimagimp
			printInfo();
			break;
		case 's': // Exemple d'utilisation des fonctions de la bibliotheque glimagimp
			actualiseImage(switchCalque(&calques, storage));
			break;
		case 'z': // Exemple d'utilisation des fonctions de la bibliotheque glimagimp
			actualiseImage(changeView(calques, storage));
			printf("Fin switch view\n");
			break;
		case 'd': // Exemple d'utilisation des fonctions de la bibliotheque glimagimp
			if(calques->prevCalque == NULL && calques->nextCalque == NULL){
				printf("Il n'y a plus de calque a supprimer.\n");
				printf("Ajouter ou fermer le logiciel a l'aide des touches \"a\" ou \"echap\"\n");
			}
			else{
				calques = delCalque(calques);
				actualiseImage(switchCalque(&calques, storage));
			}
			break;
		case 'k':
			calques->llut = delLut(calques->llut);
			resetImg(storage,calques);
			refreshLut(calques->llut,calques);
			actualiseImage(inverseImg(calques->image));
			break;
		case 'w':
			printf("Veuillez rentrez une valeur entière entre 0 et 255 : ");
			scanf("%d",&val);
			printf("Vous avez choisi : %d\n", val);

			if(val >=0 && val <=255){
				calques->llut = addlum(calques->llut,val);
				resetImg(storage,calques);
				refreshLut(calques->llut,calques);
			}
			else{
				printf("Vous n'avez pas rentré un nombre entre 0 et 255\n");
			}
			actualiseImage(inverseImg(calques->image));
			break;
		case 'x':
			printf("Veuillez rentrez une valeur entière entre 0 et 255 : ");
			scanf("%d",&val);
			printf("Vous avez choisi : %d\n", val);

			if(val >=0 && val <=255){
				calques->llut = dimlum(calques->llut,val);
				resetImg(storage,calques);
				refreshLut(calques->llut,calques);
			}
			else{
				printf("Vous n'avez pas rentré un nombre entre 0 et 255\n");
			}
			actualiseImage(inverseImg(calques->image));
			break;
		case 'c':
			printf("Veuillez rentrez une valeur entière entre 0 et 255 : ");
			scanf("%d",&val);
			printf("Vous avez choisi : %d\n", val);

			if(val >=0 && val <=255){
				calques->llut = addcon(calques->llut,val);
				resetImg(storage,calques);
				refreshLut(calques->llut,calques);
			}
			else{
				printf("Vous n'avez pas rentré un nombre entre 0 et 255\n");
			}
			actualiseImage(inverseImg(calques->image));
			break;
		case 'v':
			printf("Veuillez rentrez une valeur entière entre 0 et 255 : ");
			scanf("%d",&val);
			printf("Vous avez choisi : %d\n", val);

			if(val >=0 && val <=255){
				calques->llut = dimcon(calques->llut,val);
				resetImg(storage,calques);
				refreshLut(calques->llut,calques);
			}
			else{
				printf("Vous n'avez pas rentré un nombre entre 0 et 255\n");
			}
			actualiseImage(inverseImg(calques->image));
			break;
		case 'b':
			calques->llut = invert(calques->llut);
			resetImg(storage,calques);
			refreshLut(calques->llut,calques);
			actualiseImage(inverseImg(calques->image));
			break;
		case 'n':
			calques->llut = sepia(calques->llut);
			resetImg(storage,calques);
			greyScale(calques); // Placer ici pour que le reset image n'affecte pas le niveau de gris.
			refreshLut(calques->llut,calques);
			actualiseImage(inverseImg(calques->image));
			break;
		case 'm':
			switchMix(calques);
			break;
		case 'o':
			printf("Rentrez un nom d'image, elle sera enregistree dans le dossier images/.\n");
			printf("nom de l'image (sans .ppm): ");
			scanf("%s",saisie);
			sprintf(name, "./images/%s.ppm", saisie);
			if(calques->source == 0){
				writeppm(&(storage->album[calques->key]), name);
			}
			else{
				writeppm(calques->image, name);
			}
			break;
		case 'a': // Exemple d'utilisation des fonctions de la bibliotheque glimagimp
			// int keyCalque = getLastKey(calques);
			printf("Merci de rentrer le chemin d'une image a rajouter (elle doit etre de la meme taille que l'image initiale).\n");
			printf("chemin de l'image : ");
			scanf("%s",saisie);
			if(strstr(saisie,".ppm") != NULL){
				storage = scanImg(saisie, storage);
				calques = addCalque(storage, calques);
			}
			else{
				printf("L'image n'est pas en .ppm ou n'a pas ete trouvee\n");
			}
			afficherCalques(calques, storage);
			actualiseImage(switchCalque(&calques, storage));
			break;
		case 27: // Touche Escape
			printf("Fin du programme\n");
			quitte();
			break;
		default :
			printf("Touche non fonctionnelle\n");
	}
}

/// ///////////////////////////////////////////////////////////////////////////
/// fonction associée aux interruptions clavier speciales
/// - c : caractère saisi
/// - x,y : coordonnée du curseur dans la fenêtre
void kbdSpFunc(int c, int x, int y){
	printf("Touche speciale utilisee %d (coord souris %d/%d)\n",c,x,y);
	switch(c) {
		case 100: // touche fleche gauche
			actualiseImage(decreaseOpacity(calques, storage));
			break;
		case 102: // touche fleche droite
			actualiseImage(increaseOpacity(calques, storage));
			break;
		case GLUT_KEY_F1 : // quit
			printf("Touche F1\n");
			break;
		default :
			printf("Touche speciale non fonctionnelle\n");
	}
}

/// ///////////////////////////////////////////////////////////////////////////
/// fonction associée aux evenements souris
/// - x,y : coordonnée de la souris dans la fenêtre
void clickMouse(int button,int state,int x,int y){
	if (button == GLUT_LEFT_BUTTON) {
		printf("Button gauche ");
	}
	else if (button == GLUT_MIDDLE_BUTTON) {
		printf("Button milieu ");
	}
	else { // button == GLUT_RIGHT_BUTTON
		printf("Button droit ");
	}
	if (state == GLUT_DOWN) {
		printf("clique\n");
	}
	else { // state == GLUT_UP
		printf("relache\n");
	}
	printf("Coordonnees du point clique %d %d\n",x,y);
}

void quitte(void){
	Calque* temp = NULL;

	if(image_base != NULL){
		free(image_base);
	}
	if(calques != NULL){
		while(calques->prevCalque != NULL){
			calques = calques->prevCalque;
		}
		while(calques != NULL){
			temp = calques;
			calques = calques->nextCalque;
			if(storage != NULL){
				//free(storage->album[temp->key].type);
				//free(storage->album[temp->key].pixels);
			}
			free(temp);
		}
		free(storage->album);
		free(storage);
		storage = NULL;
		free(calques);
		calques = NULL;
	}
	exit(0);
}